#pragma once
#include<iostream>
#include<string>
#include<cstdio>
#include<cstdbool>
#include<cstring>
#include<unistd.h>
#include<sys/ipc.h>
#include<sys/shm.h>

namespace bit
{
    #define SIZE 4096
    std::string pathname = "lp";
    const int proj_id = 0;
    class Shm
    {
    protected:
        void* AttachShm()
        {
            void* shmaddr = shmat(_shmid, nullptr, 0);
            return shmaddr;
        }
        bool DetachShm()
        {
            int id = shmdt(_address);
            return id == 0;
        }
    public:
        //成员函数：
        Shm(const std::string& _pathname, const int& _proj_id)
        {
            _key = ftok(_pathname.c_str(), _proj_id);
        }
        int GetKey(){return _key;}
        int GetShmid(){return _shmid;}
        void* GetAddress(){return _address;}
        shmatt_t GetNattch()
        {
            struct shmid_ds d;
            shmctl(_shmid, IPC_STAT, &d);
            return d.shm_nattch;
        }
        void Clear(){memset(_address, 0, SIZE);}

        //纯虚函数：
        virtual void Setshmid() = 0;
    protected:
        int _key;
        int _shmid;
        void* _address;
    };
    class WriteShm : public Shm
    {
    public:
        WriteShm(const std::string& _pathname = pathname, const int& _proj_id = proj_id)
            :Shm(pathname, _proj_id)
        {
            Setshmid();
            _address = AttachShm();
            if(_address == nullptr) perror("Error Attach: ");
            else Clear();
        }
        ~WriteShm()
        {
            std::cout << "Write Detach..." << std::endl;
            if(!DetachShm())perror("Error Detach: ");
            shmctl(_shmid, IPC_RMID, nullptr);
        }
        void Setshmid() override
        {
            _shmid = shmget(_key, SIZE, IPC_CREAT | IPC_EXCL | 0660);
            if(_shmid == -1) 
            {
                perror("Error Write Setshm: ");
            }
        }
    };
    class ReadShm : public Shm
    {
    public:
        ReadShm(const std::string& _pathname = pathname, const int& _proj_id = proj_id)
            :Shm(pathname, _proj_id)
        {
            Setshmid();
            _address = AttachShm();
            if(_address == nullptr) perror("Error Attach: ");
            // error！这样写会有潜在的bug.
            // else Clear();
        }
        ~ReadShm()
        {
            std::cout << "Read Detach..." << std::endl;
            if(!DetachShm())perror("Error Detach: ");
            shmctl(_shmid, IPC_RMID, nullptr);
        }
        void Setshmid() override
        {
            _shmid = shmget(_key, SIZE, IPC_EXCL | 0660);
            if(_shmid == -1) 
            {
                perror("Error Read Setshm: ");
            }
        }
    };

    //工具函数：
    inline void PrintOnHEX(int x){printf("0x%x\n", x);}     
}